# Корутины
# Coroutines (Корутины) — это функции, которые могут быть приостановлены и возобновлены. Они позволяют контролировать моменты своей
# приостановки и возобновления работы, что делает их идеальными для сценариев асинхронного программирования, например, при выполнении
# длительных задач, ожидании данных от внешних ресурсов или выполнении других корутин.

 
# Пишем первый асинхронный код. Ключевые слова async и await.
# Для создания корутины нужно использовать ключевое слово async.
# import asyncio


# async def example_coroutine():
#     print("Hello from coroutine!")

# Если функция начинается с конструкции async def, она является асинхронной функцией, и внутри неё можно использовать ключевое 
# слово await для вызова других корутин или асинхронных операций внутри тела этой корутины. Использование ключевого слова 
# await вне корутины вызовет ошибку. 

# import asyncio


# async def example_coroutine():
#     await asyncio.sleep(1)  # запускаем внутри корутины асинхронную функцию sleep()
#     print("Hello from coroutine!")


#Корутина может принимать аргументы и возвращать значения. Правила передачи аргументов аналогичны правилам для обычных синхронных функций. 

# import asyncio


# async def example_coroutine(number, *args, **kwargs):
#     await asyncio.sleep(1)  # запускаем внутри корутины асинхронную функцию sleep()
#     print(f"Hello from coroutine {number}!")
#     return f"Корутина {number} завершила работу"
# asyncio.run(example_coroutine(1, 2, 3, 4))

# Запуск корутины. Функция asyncio.run().
# Мы создали первую корутину example_coroutine(). Для ее запуска нужно использовать функцию asyncio.run().
# Если попытаться запустить корутину, как обычную функцию, выполнение корутины не начнется. Вместо этого будет создан объект корутины. 


# import asyncio
# #НЕ ПРАВИЛЬНО
# async def example_coroutine():
#     print("Hello from coroutine!")

# example_coroutine()  # создан объект корутины example_coroutine(), корутина не запущена!


# #ПРАВИЛЬНО
# async def example_coroutine():
#     print("Hello from coroutine!")

# asyncio.run(example_coroutine())  # корутина example_coroutine() запущена. 


# Точка входа. Запуск нескольких корутин.
# В предыдущем примере мы создали  корутину example_coroutine() и запустили ее с помощью функции asyncio.run(). В реальных асинхронных приложениях
# есть различные корутины, каждая из которых выполняется много раз. Для того чтобы реализовать возможность запуска множества задач, а не одной,
# необходимо создать еще одну корутину, которая будет являться *точкой входа для асинхронного приложения. Из данной корутины будут запущены все
# необходимые корутины или задачи. 

# *Точка входа в асинхронную программу означает место, где начинается асинхронное выполнение кода, т.е. первая запускаемая корутина. Для такой
# корутины обычно используется имя main().

# Попробуем изменить наш код и запустить корутину example_coroutine() через точку входа. Для этого создадим корутину main(), внутри нее запустим
# example_coroutine().
#Для запуска корутин и задач из других корутин нужно использовать ключевое слово await.

# import asyncio


# async def example_coroutine():
#     await asyncio.sleep(1) 
#     print("Hello from coroutine!")

# async def main():
#     await example_coroutine() # запускаем example_coroutine() и ждем выполнения

# asyncio.run(main())  # Точка входа

# Мы увидим то же самое поведение, что и в примере выше. Корутина example_coroutine() выполнится и на экран будет выведено сообщение:

# Hello from coroutine!

# Но теперь мы получили код, который можно масштабировать. Внутри main() мы можем запустить корутину example_coroutine()
# нужное нам число раз или запустить из main() другую корутину.
import asyncio


async def example_coroutine():
    print("Hello from coroutine!")
    await asyncio.sleep(1)

async def main():
    for _ in range(10):
        await example_coroutine()

asyncio.run(main())  

# В этом примере мы запускаем корутину example_coroutine() 10 раз. Вы можете заметить, что каждая корутина выполняется последовательно,
# а не конкурентно. Время выполнения такой программы составит чуть больше 10 секунд. Такое поведение пока не соответствует тому, что мы
# хотим получить от асинхронного программирования. Как запустить корутины конкурентно  рассмотрим в следующем уроке, а пока предлагаем
# ответить на несколько вопросов и потренироваться в написании простых корутин.